package fr.zadoka.zadokadna;

import java.lang.ref.WeakReference;
import java.util.Calendar;
import java.util.GregorianCalendar;

import fr.zadoka.zadokadna.Loader.TaskCallback;
import fr.zadoka.zadokadna.Loader.UrlImageLoaderTask;
import fr.zadoka.zadokadna.Util.CalendarUtil;
import fr.zadoka.zadokadna.db.ZadokaDatabaseContract;
import Cache.ZadokaImageCache;
import android.app.Activity;
import android.app.DatePickerDialog;
import android.app.DatePickerDialog.OnDateSetListener;
import android.app.Dialog;
import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.DatePicker;
import android.widget.ImageView;
import android.widget.Toast;



public class MainActivity extends ActionBarActivity implements 
	OnPageChangeListener, OnDateSetListener, LoaderCallbacks<Cursor>
{

	private final static String SAVED_IMAGE_DATE_KEY = "IMAGE_DATE";

	private static final int FAVORITE_LOADER = 0;

	private static final String[] PROJECTION =
	    {
			ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IMAGE_DATE,
			ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IS_FAVORITE
	    };

	private static final String FAVORITE_IMAGE_DATE = "FAVORITE_IMAGE_DATE";

	private MainPageAdapter mSectionsPagerAdapter;

	private ViewPager mViewPager;
	
	private ZadokaFavorites zadokaFavorite;
	
	private Boolean mCurrentImageIsFavorite = false;

	private ZadokaNavigationDrawer mNavigationDrawer;
	
	private GregorianCalendar mLastDate;
	
	/**
	 * ActionBarActivity methods
	 */
	
	/**
	 * Save the last date that was displayed
	 */
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		// TODO Auto-generated method stub
		super.onSaveInstanceState(outState);
		CalendarUtil.LogDate("fr.zadoka.zadokadna.", "onSaveInstanceState ", mSectionsPagerAdapter.getPositionDate(mViewPager.getCurrentItem()));

		outState.putLong(SAVED_IMAGE_DATE_KEY, mSectionsPagerAdapter.getPositionDate(mViewPager.getCurrentItem()).getTimeInMillis());
	}
	
	/**
	 * Create the view layout (ViewPager, PageAdapter, Drawer)
	 * Create the data component (Favorite file manager, FavoriteProvider)
	 * 
	 */
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		//create the view layout
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// Create the adapter that will return a fragment for each date
		mSectionsPagerAdapter = new MainPageAdapter(getSupportFragmentManager());

		//set the start date of the PageAdapter
		mLastDate = null;
		if ((savedInstanceState != null))
			mLastDate = CalendarUtil.millisecondsToGregorianCalendar(savedInstanceState.getLong(SAVED_IMAGE_DATE_KEY, System.currentTimeMillis()));
		else
			mLastDate = new GregorianCalendar();
		CalendarUtil.LogDate("fr.zadoka.zadokadna.", "on create ", mLastDate);

		// Set up the ViewPager with the sections adapter.
		mViewPager = (ViewPager) findViewById(R.id.pager);
		mViewPager.setAdapter(mSectionsPagerAdapter);		
		mViewPager.setOnPageChangeListener(this);
		
	    //set up the drawer
	    mNavigationDrawer = new ZadokaNavigationDrawer(this);

	    //set up the favorite file manager
	    zadokaFavorite = new ZadokaFavorites(this);
	       
		// Initializes the CursorLoader
		Bundle bundle = new Bundle();
		bundle.putLong(FAVORITE_IMAGE_DATE, mLastDate.getTimeInMillis());
        getSupportLoaderManager().initLoader(FAVORITE_LOADER, bundle , this);		

        //pass the favorite file manager to the fragment
	    MainPlaceholderFragment.mFavorites = zadokaFavorite;	    
	}
	
	/**
	 * Refresh the current image state when the activity starts
	 */
	@Override
	protected void onStart() {
		super.onStart();
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		CalendarUtil.LogDate("fr.zadoka.zadokadna.", "onResume ", mLastDate);
		
		mViewPager.setCurrentItem(mSectionsPagerAdapter.getDatePosition(mLastDate));
		refreshCurrentImage();	
	}


	/**
	 * Display the date picker dialog
	 */
	private void displayDateDialog() {
		// TODO Auto-generated method stub
		DialogFragment newFragment = new DatePickerFragment();
	    newFragment.show(getSupportFragmentManager(), "datePicker");		
	}
	

	/**
	 * Generate the ActionBar menu layout
	 */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {

	    MenuInflater inflater = getMenuInflater();
	    inflater.inflate(R.menu.main, menu);
	    return super.onCreateOptionsMenu(menu);
	}

	/**
	 * Manage the clicks on the action bar/drawer menu items 
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		//Manage the drawer items
		if (mNavigationDrawer.onOptionsItemSelected(item)) {
	          return true;
	    }
		
		//manage the action bar items
	    switch (item.getItemId()) 
	    {
	    	//favorite/unfavorite an image
	    	case R.id.action_favorite :
	    		changeFavorite();
	    		return true;
	    	//search an image for a given date
	    	case R.id.action_daily_search:
	    		displayDateDialog();
	    		return true;
	    	default:
	    		return super.onOptionsItemSelected(item);
	    }
	
	}
	
	/**
	 * Add or remove an image image from/to the favorites
	 */
	private void changeFavorite() {

		//date of the displayed image
		GregorianCalendar imageDate = mSectionsPagerAdapter.getPositionDate(mViewPager.getCurrentItem());
		
		if(!mCurrentImageIsFavorite)
		{
			//not a favorite yet => add it
			
			//create the values to insert into the db
			ContentValues values = new ContentValues();
			values.put(ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IMAGE_DATE, CalendarUtil.GregorianCalendarToString(imageDate));
			values.put(ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IS_FAVORITE, 1);
			
			//insert the new image in the favorite db
			getContentResolver().insert(ZadokaDatabaseContract.ZadokaFavoriteContract.FAVORITE_TABLE_CONTENTURI, values);
			
			//save the image to the favorite file manager
			zadokaFavorite.saveImage(imageDate, MainPlaceholderFragment.mImageCache.getBitmapFromMemCache(mSectionsPagerAdapter.getPositionDate(mViewPager.getCurrentItem())));
			
			//tell the activity that this image is a favorite image
			OnFavorite(true);
		}
		else
		{
			//is already a favorite => remove it
			
			//create the delete where clause
			String where = ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IMAGE_DATE + " = ?";
			String[] whereArgs = new String[]{CalendarUtil.GregorianCalendarToString(imageDate)};
			
			//delete the image from the favorite db
			getContentResolver().delete(ZadokaDatabaseContract.ZadokaFavoriteContract.FAVORITE_TABLE_CONTENTURI, 
										where , 
										whereArgs );
			
			//delete the image from the favorite file manager
			zadokaFavorite.deleteImage(imageDate);
			
			//tell the activity that this image is no longer a favorite
			OnFavorite(false);
		}
	}
	
	/**
	 * Handle the Favorite state change
	 * @param isFavorite: indicates the new favorite state
	 */
	public void OnFavorite(Boolean isFavorite) {
		
		//display a toast to tell the user the image has benn added/removed to/from the favorites
		StringBuilder sb = new StringBuilder();
		if (isFavorite)
			sb.append("Added to ");
		else
			sb.append("Removed from ");
		sb.append("the favorite");
		int duration = Toast.LENGTH_SHORT;

		Toast toast = Toast.makeText(getApplicationContext(), sb, duration);
		toast.show();	
		
		//set the internal flag
		mCurrentImageIsFavorite = isFavorite;

		//refresh the action bar display
		supportInvalidateOptionsMenu();		
	}
	
	/**
	 * Displays the acvtion bar mnenu items
	 */
	@Override	
	public boolean onPrepareOptionsMenu(Menu menu) {
		//manage the favorite action item
		//display as favorite or not, depending on mCurrentImageIsFavorite
	
		MenuItem favoriteAction = menu.findItem(R.id.action_favorite);		
		if (mCurrentImageIsFavorite)
			favoriteAction.setIcon(R.drawable.ic_action_accept);
		else
			favoriteAction.setIcon(R.drawable.ic_action_important);

		//do not display teh action bar items if the drawer is open
		MenuItem serachAction = menu.findItem(R.id.action_daily_search);
		boolean isDrawerOpen = mNavigationDrawer.isOpen();
		favoriteAction.setVisible(!isDrawerOpen);
		serachAction.setVisible(!isDrawerOpen);
		
		return super.onPrepareOptionsMenu(menu);

	}
	
	/**
	 * Refresh the display with the new image
	 */
	private void refreshCurrentImage()
	{
		//get the favorite entry for the current date
		Bundle bundle = new Bundle();
		bundle.putLong(FAVORITE_IMAGE_DATE, mSectionsPagerAdapter.getPositionDate(mViewPager.getCurrentItem()).getTimeInMillis());
        getSupportLoaderManager().restartLoader(FAVORITE_LOADER, bundle , this);		
		
        //set the date in the action bar
		getSupportActionBar().setTitle(mSectionsPagerAdapter.getPageTitle(mViewPager.getCurrentItem()));
	}
	
	/**
	 * LoaderCallbacks<Cursor> methods
	 */
	@Override
	public Loader<Cursor> onCreateLoader(int loaderID, Bundle bundle) {
		 /*
         * Takes action based on the ID of the Loader that's being created
         */
        switch (loaderID) {
            case FAVORITE_LOADER:
            	// Returns a new CursorLoader
            	//we need the date of the favorite to load
            	if ((bundle == null) || !bundle.containsKey(FAVORITE_IMAGE_DATE))
            		return null;
            	GregorianCalendar date = CalendarUtil.millisecondsToGregorianCalendar(bundle.getLong(FAVORITE_IMAGE_DATE));
            	return new CursorLoader(
                        this,                                     // Context
                        ZadokaDatabaseContract.ZadokaFavoriteContract.FAVORITE_TABLE_CONTENTURI,  // Table to query
                        PROJECTION,                                        // Projection to return
                        getFavoriteSelectionClause(),                      
                        getFavoriteSelectionArguments(date),               
                        null                                              
            );
            default:
                // An invalid id was passed in
                return null;

        }		
    }

	/**
	 * returns the favorite SQL selection arguments string based on the given date
	 * @param date: date to pass as argunent
	 * @return
	 */
	private String[] getFavoriteSelectionArguments(GregorianCalendar date) {
		return new String[]{CalendarUtil.GregorianCalendarToString(date)};
	}

	/**
	 * returns the favorite SQL selection clause ("where") 
	 * @return
	 */
	private String getFavoriteSelectionClause() {
		return ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IMAGE_DATE + "= ? AND " +  ZadokaDatabaseContract.ZadokaFavoriteContract.ZADOKA_DNA_IS_FAVORITE + " = 1";	
	}

	/**
	 * Refresh the action bar menu items when the favorite is loaded
	 */
	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
		mCurrentImageIsFavorite = cursor.getCount() == 1;
		supportInvalidateOptionsMenu();		
	}


	@Override
	public void onLoaderReset(Loader<Cursor> arg0) {
		
	}

	/**
	 * 
	 * Displays a dialog with a date picker
	 *
	 */
	public static class DatePickerFragment extends DialogFragment {

		@Override
		public Dialog onCreateDialog(Bundle savedInstanceState) {
			// Use the current date as the default date in the picker
			final Calendar c = Calendar.getInstance();
			int year = c.get(Calendar.YEAR);
			int month = c.get(Calendar.MONTH);
			int day = c.get(Calendar.DAY_OF_MONTH);
			
			// Create a new instance of DatePickerDialog and return it
			return new DatePickerDialog(getActivity(), (OnDateSetListener) getActivity(), year, month, day);
		}
		
	}	
	/**
	 * OnDateSetListener methods
	 */
	
	/**
	 * restart the viewpager when a new date is selected
	 */
	@Override
	public void onDateSet(DatePicker view, int year, int monthOfYear,
			int dayOfMonth) {
		GregorianCalendar newDate = new GregorianCalendar(year, monthOfYear, dayOfMonth);
		mViewPager.setCurrentItem(mSectionsPagerAdapter.getDatePosition(newDate));
		
	}
	
	

	// OnPageChangeListener
	
	@Override
	public void onPageScrollStateChanged(int arg0) {
	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) {
		
	}

	/**
	 * refresh the current display when a new image is displayed
	 */
	@Override
	public void onPageSelected(int position) {
		// TODO Auto-generated method stub
		refreshCurrentImage();
	}
	
	/**
	 * A {@link FragmentPagerAdapter} that returns a fragment displaying the daily image
	 */
	private class MainPageAdapter extends FragmentStatePagerAdapter {

		/**
		 * constructor
		 * @param fm
		 * @param startDate
		 */
		public MainPageAdapter(FragmentManager fm) {
			super(fm);
		}
		
		/**
		 * return the date in form of dd_mm_yyyy
		 */
		@Override
		public CharSequence getPageTitle(int position) {
			return CalendarUtil.GregorianCalendarToString(getPositionDate(position));
		}

		/**
		 * returns the position of an object in the adapter
		 */
		@Override
		public int getItemPosition(Object object) {
			// we always return POSITION_NONE to force the internal state refresh
			return POSITION_NONE;
		}
	
		/**
		 * Get a new fragment to display
		 */
		@Override
		public Fragment getItem(int position) {
			// getItem is called to instantiate the fragment for the given page.
			// Return a PlaceholderFragment (defined as a static inner class
			// below).
			
			GregorianCalendar positionDate = getPositionDate(position);
			
			return MainPlaceholderFragment.newInstance(positionDate);
		}

		/**
		 * Get the date of a given page
		 * @param position
		 * @return
		 */
		public GregorianCalendar getPositionDate(int position) {
			
			GregorianCalendar positionDate = new GregorianCalendar();
			positionDate.add(GregorianCalendar.DAY_OF_MONTH, 0 - position);
			return positionDate;
		}

		/**
		 * Number of pages that are displayed
		 */
		@Override
		public int getCount() {

			int nbDays = CalendarUtil.numberOfDaysBetween(new GregorianCalendar(), new GregorianCalendar(2014, GregorianCalendar.MAY, 15));
			Log.i("fr.zadoka.zadokadna","Number of days" + Integer.toString(nbDays));
			return nbDays;
		}
		
		public int getDatePosition(GregorianCalendar newDate)
		{
			return CalendarUtil.numberOfDaysBetween(new GregorianCalendar(), newDate);
		}
	}	
	
	/**
	 * 
	 * Fragment that wil display the daily image
	 *
	 */
	public static class MainPlaceholderFragment extends Fragment implements TaskCallback<Bitmap> {

		//date of the image that is displayed
		private static final String ARG_PAGE_DATE = "page_date";
		//global daily image cache
		private static ZadokaImageCache mImageCache;
		//favorite manager
		public static ZadokaFavorites mFavorites = null;
		//ImageView where the daily image is displayed
		private WeakReference<ImageView> mImageView;	
		//date of the image
		private GregorianCalendar mImageDate;

		@Override
		public void onAttach(Activity activity) {
			// TODO Auto-generated method stub
			super.onAttach(activity);
			
			Log.i("ZadokaDna", "getting image cache");
			//initialize the global cache
			MainPlaceholderFragment.mImageCache = ZadokaImageCache.getInstance(getFragmentManager());				
		}

		/**
		 * Returns a new instance of this fragment for the given date.
		 */
		public static MainPlaceholderFragment newInstance(GregorianCalendar positionDate) {
			
			MainPlaceholderFragment fragment = new MainPlaceholderFragment();
			Bundle args = new Bundle();
			args.putLong(ARG_PAGE_DATE, positionDate.getTimeInMillis());
			fragment.setArguments(args);
			return fragment;
		}

		public MainPlaceholderFragment() {
		}


		@Override
		public View onCreateView(LayoutInflater inflater, ViewGroup container,
				Bundle savedInstanceState) {
			
			//load the fragment layout
			View rootView = inflater.inflate(R.layout.fragment_main, container,
					false);
			mImageView = new WeakReference<ImageView>((ImageView) rootView.findViewById(R.id.imageView1));
			
			//load the image for the asked date
			Bundle args = getArguments();
			loadImage(args.getLong(ARG_PAGE_DATE, new GregorianCalendar().getTimeInMillis()));	
			
			return rootView;
		}

		private void loadImage(long date) {

			//convert the time in milliseconds to a gregorian calendar
			GregorianCalendar imageDate = new GregorianCalendar();		
			imageDate.setTimeInMillis(date);
			mImageDate = imageDate;
			
			CalendarUtil.LogDate("fr.zadoka.zadokadna.MainPlaceholderFragment.onCreateView", "Executing with : ", imageDate);
			
			//start the async task
			new UrlImageLoaderTask(mImageCache, this).execute(imageDate);			
		}

		@Override
		public void OnResult(Bitmap result) {

			//if no image could be loaded, try to find it in the favorite, or load the default one
			if (result == null)
			{
				if (mFavorites != null)
					result = mFavorites.loadImage(mImageDate);
				//if no image could be loaded, load the default one
				if (result == null)
					result = BitmapFactory.decodeResource(getResources(), R.drawable.missingzadoka);
			}

			if (mImageView.get() != null)
				mImageView.get().setImageBitmap(result);
		}

		
	}
}
